﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

/// <summary>
/// 攻击脚本
/// </summary>
public class AttackerScript : MonoBehaviour
{

	private BaseItemScript _baseItem;
	private BaseItemScript _currentTarget;
	private Vector3 _currentTargetPoint;
	/// <summary>
	/// 设置数据
	/// </summary>
	/// <param name="baseItem">基础物品脚本</param>
	public void SetData(BaseItemScript baseItem)
	{
		this._baseItem = baseItem;
	}
	/// <summary>
	/// 攻击最近目标
	/// </summary>
	public void AttackNearestTarget()
	{
		//Debug.Log("AttackNearestTarget");
		BaseItemScript target = _GetNearestTargetItem();
		//Debug.Log(target + "target");
		if (target != null)
		{
			this.Attack(target);
		}
		else
		{
			int t = 0;
			//Debug.LogError("no target");
		}
	}
	/// <summary>
	/// 攻击目标
	/// </summary>
	/// <param name="target">目标</param>
	public void Attack(BaseItemScript target)
	{
		this._baseItem.Walker.OnBetweenWalk = null;

		if (target != null)
		{
			this._currentTarget = target;
			//StartCoroutine(CheckTarget());

			//  Vector3[] outerCells = target.GetOuterCells();
			Vector2Int[] outerCells = GridManager.instance.GetOuterGrids(target.GetPosition(), target.itemData.gridSize, target.itemData.gridSize).ToArray();
			// Debug.Log(outerCells.Length);
			if (outerCells.Length > 0)
			{
				//finding nearest outer cell
				Vector3 nearestCell = Vector3.one * 999999;
				float smallerDistance = 999999;
				for (int index = 0; index < outerCells.Length; index++)
				{
     //               Debug.Log(outerCells[index]);
					//Debug.Log(GridManager.instance.GetWorldPositionOfGridCenter(outerCells[index]));
                    float distance = Vector3.Distance(this._baseItem.GetPosition(), GridManager.instance.GetWorldPositionOfGridCenter(outerCells[index]));
					if (distance < smallerDistance)
					{
						smallerDistance = distance;
						// nearestCell = outerCells[index];
						nearestCell = GridManager.instance.GetWorldPositionOfGridCenter(outerCells[index]);
					}
				}

				this._currentTargetPoint = nearestCell;
				//var p = GameObject.CreatePrimitive(PrimitiveType.Cube);
    //            p.transform.position = nearestCell;
				//Debug.Log(nearestCell);

				this._baseItem.Walker.WalkToPosition(_currentTargetPoint);
				this._baseItem.Walker.OnFinishWalk += this.AttackLoop;

				//check any walls on root
				BaseItemScript nearestWallOnPath = this._baseItem.Walker.GetNearestWallOnPath();
				if (nearestWallOnPath != null)
				{
					this._currentTarget = nearestWallOnPath;
					//					Debug.Log (nearestWallOnPath);
				}

			}
				
			if (this._baseItem.itemData.configuration.attackRange > 0)
			{
				this._baseItem.Walker.OnBetweenWalk += this.CheckTargetBeyondRange;
				//check on start walk because the unit will already in range of target maybe
				this.CheckTargetBeyondRange();
			}
		}
	}

	/// <summary>
	/// 攻击循环
	/// </summary>
	public void AttackLoop()
	{
		if (this._baseItem.isDestroyed)
		{
			return;
		}
		// Debug.Log(_baseItem.state);
		if (this._currentTarget.healthPoints > 0)
		{
			// Debug.Log(_currentTarget.healthPoints);
			this._baseItem.LookAt(this._currentTarget);
			this._baseItem.SetState(Common.State.ATTACK);
			this.StartCoroutine(_HitTarget());
		}
		else
		{
			this._baseItem.SetState(Common.State.IDLE);
			this._baseItem.Walker.OnFinishWalk -= this.AttackLoop;
			this.AttackNearestTarget(); //start again
		}
	}
   private void Start()
   {
		StartCoroutine(_CheckTarget());
   }
	private void OnDestroy()
	{
		StopAllCoroutines();
   }
   private IEnumerator _CheckTarget()
	{
		WaitForSeconds waitDotFive = new WaitForSeconds(.5f);
		while (true)
		{
			yield return waitDotFive;
			if (_currentTarget == null)
			{
				continue;
			}
			if (_currentTarget.healthPoints <= 0 || _currentTarget.isDestroyed)
			{
				this._baseItem.Walker.CancelWalk();
				this.AttackLoop();
			}
		}
	}
	/// <summary>
	/// 检查目标是否超出范围
	/// </summary>
	public void CheckTargetBeyondRange()
	{
		//		Debug.Log ("CheckTargetBeyondRange");
		if (Vector3.Distance(_currentTarget.GetCenterPosition(), this._baseItem.GetPosition()) <= this._baseItem.itemData.configuration.attackRange)
		{
			this._baseItem.Walker.CancelWalk();
			this.AttackLoop();
		}
	}

	public void CheckWallsOnRoot()
	{
		//		Debug.Log ("CheckWallsOnRoot");
		if (Vector3.Distance(_currentTarget.GetCenterPosition(), this._baseItem.GetPosition()) <= this._baseItem.itemData.configuration.attackRange)
		{
			this._baseItem.Walker.CancelWalk();
			this.AttackLoop();
		}
	}
	/// <summary>
	/// 攻击目标
	/// </summary>
	/// <returns>The target.</returns>
	private IEnumerator _HitTarget()
	{
		// Debug.Log("hit");
		yield return new WaitForSeconds(1.0f);
		if (!this._baseItem.isDestroyed)
		{
			this._currentTarget.OnReceiveHit(this._baseItem);
			this.AttackLoop();

			this._PlayHitSound();
		}
	}
	/// <summary>
	/// 播放攻击音效
	/// </summary>
	private void _PlayHitSound()
	{
		AudioClip clip = null;
		if (this._baseItem.itemData.name == "SwordMan")
			clip = SoundManager.instance.Sword;
		else if (this._baseItem.itemData.name == "Archer" || this._baseItem.itemData.name == "ArcherTower")
			clip = SoundManager.instance.Bow;

		SoundManager.instance.PlaySound(clip, false);
	}
	/// <summary>
	/// 获取最近目标物品
	/// </summary>
	/// <returns>The nearest target item.</returns>
	private BaseItemScript _GetNearestTargetItem()
	{
		BaseItemScript nearestItem = null;
		float nearestDistance = 999999;
		//Debug.Log(SceneManager.instance.GetAllItems().Count);
		var items = SceneManager.instance.GetAllItems();
		//foreach (BaseItemScript item in SceneManager.instance.GetAllItems())
		for(int i = 0; i < items.Count; i++)
		{
			var item = items[i];
			if (item == null)
				continue;
			if (item == this._baseItem)
			{
				continue;
			}

			if (item.itemData.configuration.isCharacter)
			{
				continue;
			}

			if (item.isDestroyed)
			{
				continue;
			}

			if (item.itemData.name == "Wall")
			{
				continue;
			}

			float d = Vector3.Distance(item.GetPosition(), this._baseItem.GetPosition());
			if (d < nearestDistance)
			{
				nearestDistance = d;
				nearestItem = item;
			}
		}
		//Debug.Log("Near Item :"+ nearestItem);
		return nearestItem;
	}

}
